package l2ft.gameserver.model.entity.events.impl.fightclub;

import java.util.ArrayList;
import java.util.Calendar;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;

import javolution.util.FastMap;
import l2ft.commons.collections.MultiValueSet;
import l2ft.commons.threading.RunnableImpl;
import l2ft.gameserver.ThreadPoolManager;
import l2ft.gameserver.model.Creature;
import l2ft.gameserver.model.Player;
import l2ft.gameserver.model.Skill;
import l2ft.gameserver.model.entity.events.fightclubmanager.FightClubPlayer;
import l2ft.gameserver.model.entity.events.fightclubmanager.FightClubTeam;
import l2ft.gameserver.model.entity.events.fightclubmanager.FightClubLastStatsManager.FightClubStatType;
import l2ft.gameserver.model.entity.events.impl.AbstractFightClub;
import l2ft.gameserver.model.instances.NpcInstance;
import l2ft.gameserver.utils.Location;

public class ConquestEvent extends AbstractFightClub
{
	private static final int NON_CAPTURED_FLAG_ID = 35611;
	private static final int[] TEAM_FLAG_ID = {35608, 35609, 35610};
	
	private final int _badgesCaptureFlag;
	private final double _playersMultipleToStartCapturing;
	private final int _totalCaptureTime;
	private final int _maxRadiusToCapture;
	private final int _maxHeightToCapture;
	
	
	private Flag[] _spawnedFlags;
	
	public ConquestEvent(MultiValueSet<String> set)
	{
		super(set);
		_badgesCaptureFlag = set.getInteger("badgesCaptureFlag");
		_playersMultipleToStartCapturing = set.getDouble("playersMultipleToStartCapturing");
		_totalCaptureTime = set.getInteger("totalCaptureTime");
		_maxRadiusToCapture = set.getInteger("maxRadiusToCapture");
		_maxHeightToCapture = set.getInteger("maxHeightToCapture");
	}
	
	@Override
	public void onKilled(Creature actor, Creature victim, Skill skill)
	{
		if(actor != null && actor.isPlayable())
		{
			FightClubPlayer realActor = getFightClubPlayer(actor.getPlayer());
			if(victim.isPlayer())
			{
				realActor.increaseKills(true);
				updatePlayerScore(realActor);
				sendMessageToPlayer(realActor, MESSAGE_TYPES.HERO, "You have killed "+victim.getName());
			}
			else if(victim.isPet())
			{
				
			}
			actor.getPlayer().sendUserInfo();
		}
		
		if(victim.isPlayer())
		{
			FightClubPlayer realVictim = getFightClubPlayer(victim);
			realVictim.increaseDeaths();
			if(actor != null)
				sendMessageToPlayer(realVictim, MESSAGE_TYPES.HERO, "You have been killed by "+actor.getName());
			victim.getPlayer().sendUserInfo();
		}
		
		super.onKilled(actor, victim, skill);
	}
	
	@Override
	public void startRound()
	{
		super.startRound();
		
		Location[] keyLocs = getMap().getKeyLocations();
		_spawnedFlags = new Flag[keyLocs.length];
		
		for(int i = 0;i<keyLocs.length;i++)
		{
			NpcInstance npc = spawnNpc(NON_CAPTURED_FLAG_ID, keyLocs[i], 0);
			Flag flag = new Flag();
			flag._npc = npc;
			flag._owner = null;
			flag._percentOfAcquisition = 0;
			_spawnedFlags[i] = flag;
		}
		
		ThreadPoolManager.getInstance().schedule(new CheckAcquisition(), 1000L);
	}
	
	@Override
	public void stopEvent()
	{
		super.stopEvent();
		
		for(Flag flag : _spawnedFlags)
			flag._npc.deleteMe();
		_spawnedFlags = null;
	}
	
	
	private void addAcquisition(Flag flag, List<FightClubPlayer> fPlayersNear, FightClubTeam winner)
	{
		//If taker changed, progress is set to 0
		if(flag._acquisitionWinner != winner)
			flag._percentOfAcquisition = 0;
		flag._acquisitionWinner = winner;
		
		//Increasing progress
		if(flag._owner != null && flag._owner.equals(winner))
		{
			flag._percentOfAcquisition -= (int)Math.round(100./_totalCaptureTime);
			flag._percentOfAcquisition = Math.max(0, flag._percentOfAcquisition);
		}
		else
			flag._percentOfAcquisition += (int)Math.round(100./_totalCaptureTime);
		
		if(flag._percentOfAcquisition >= 100)
		{
			Location npcLoc = flag._npc.getLoc();
			flag._npc.deleteMe();
			//Spawning new flag
			flag._npc = spawnNpc(TEAM_FLAG_ID[winner.getIndex()-1], npcLoc, 0);
			FightClubTeam oldOwner = flag._owner;
			flag._owner = winner;
			//Setting progress to 0
			flag._percentOfAcquisition = 0;
			//Saving time
			flag._lastScoreIncreasedTime = System.currentTimeMillis();
			
			if(oldOwner != null)
			{
				sendMessageToTeam(oldOwner, MESSAGE_TYPES.CRITICAL, "One of your Flags has been Captured by "+winner.getName()+" Team!");
				sendMessageToTeam(winner, MESSAGE_TYPES.CRITICAL, "You have Captured Flag from "+oldOwner.getName()+" Team!");
			}
			else
			{
				sendMessageToTeam(winner, MESSAGE_TYPES.CRITICAL, "You have Captured new Flag!");
			}
			
			for(FightClubPlayer fPlayerNear : fPlayersNear)
				if(fPlayerNear.getTeam().equals(winner))
					fPlayerNear.increaseEventSpecificScore("capturedFlag");
		}
		else
		{
			//updating npc title
			flag._npc.setTitle(flag._percentOfAcquisition+"% -> "+winner.getName()+" Team");
			flag._npc.broadcastCharInfo();
		}
	}
	
	private void checkAcquisition(Flag flag)
	{
		NpcInstance npc = flag._npc;
		List<Creature> creaturesNear = npc.getAroundCharacters(_maxRadiusToCapture, _maxHeightToCapture);
		
		List<FightClubPlayer> fPlayersNear = new ArrayList<>();
		Map<FightClubTeam, Integer> fTeamPowers = new FastMap<>();//Team and How many players from it are near
		for(Creature c : creaturesNear)
			if(c.isPlayer() && c.getPlayer().isInFightClub())
			{
				FightClubPlayer fPlayer = getFightClubPlayer(c);
				if(fPlayer == null || fPlayer.isAfk())
					continue;
				FightClubTeam fTeam = fPlayer.getTeam();
				if(!fTeamPowers.containsKey(fTeam))
					fTeamPowers.put(fTeam, 1);
				else
					fTeamPowers.put(fTeam, fTeamPowers.get(fTeam)+1);
			}
		
		FightClubTeam winner = null;
		int powerOfWinner = 0;
		for(Entry<FightClubTeam, Integer> entry : fTeamPowers.entrySet())
		{
			if(entry.getValue() > powerOfWinner*_playersMultipleToStartCapturing)
			{
				winner = entry.getKey();
				powerOfWinner = entry.getValue();
			}
			else if(powerOfWinner <= entry.getValue()*_playersMultipleToStartCapturing)
			{
				winner = null;
			}
		}
		
		if(winner != null)
			addAcquisition(flag, fPlayersNear, winner);
	}
	
	private class CheckAcquisition extends RunnableImpl
	{
		@Override
		public void runImpl() throws Exception
		{
			if(_spawnedFlags == null)
				return;
			
			long currentTime = System.currentTimeMillis();
			for(Flag flag : _spawnedFlags)
			{
				checkAcquisition(flag);
				if(flag._owner != null && flag._lastScoreIncreasedTime + 60000L <= currentTime)
				{
					flag._owner.incScore(1);
					updateScreenScores();
					flag._lastScoreIncreasedTime = currentTime;
					System.out.println(Calendar.getInstance().get(Calendar.MINUTE)+":"+Calendar.getInstance().get(Calendar.SECOND));
				}
			}
			
			ThreadPoolManager.getInstance().schedule(this, 1000L);
		}
	}

	private class Flag
	{
		private NpcInstance _npc;
		private FightClubTeam _owner;
		private int _percentOfAcquisition;
		private long _lastScoreIncreasedTime;
		private FightClubTeam _acquisitionWinner;
	}
	
	@Override
	protected int getBadgesEarned(FightClubPlayer fPlayer, int currentValue)
	{
		currentValue += addMultipleBadgeToPlayer(fPlayer, FightClubStatType.CONQUARE_FLAG, fPlayer.getEventSpecificScore("capturedFlag"), _badgesCaptureFlag, fPlayer.getSecondsSpentOnEvent());
		return super.getBadgesEarned(fPlayer, currentValue);
	}
	
	@Override
	public String getVisibleTitle(Player player, String currentTitle, boolean toMe)
	{
		FightClubPlayer fPlayer = getFightClubPlayer(player);
		
		if(fPlayer == null)
			return currentTitle;
		
		return "Kills: "+fPlayer.getKills(true)+" Deaths: "+fPlayer.getDeaths();
	}
}
